#include "mem_pool.h"
#include "lock.h"
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <malloc.h>

#define UNIT_N 10240
#define UNIT_X (2560)
#define THREADS 4
#define LOOP 3000 

#include "mln_alloc.h"
mln_alloc_t *pool;
int _err_cnt[8] = {0,0,0,0,0,0,0,0};
volatile int lock = 0;
volatile int g_num = 0;

typedef void*(*px_t);

//测试分配+free
void* thread_func(void* arg) {
    int N = UNIT_X*8;
    void* _p = malloc(N * sizeof(void*));
    memset(_p, 0, N * sizeof(void*));
    px_t p = (px_t)_p;
    //printf("%p,%p\n", p,p+1);

    int t[8] = {4,8,16,32,64,128,256,512};
    
    for (int n = 0; n < UNIT_X; n++) {
        
        for (int i = 0; i < 8; i++) {
            int size = __sync_add_and_fetch(&g_num,1);
            int _size = (size&(t[i]-1)) + t[i];
            //printf("[%d]size=%d\n", i,size);
            *p = mem_pool_alloc(_size);
            if (*p) {
                memset(*p, 0, _size);
                //printf("[%d]size=%d %p\n", i,size,*p);
            } else{
                __sync_add_and_fetch(&_err_cnt[i],1);
                //printf("error size=%d\n", size);
            }
            p++;
        }
    }
    int k = 0;
    p = (px_t)_p;
    while (k < N) {
        if (p[k]) {
            mem_pool_free(p[k]);
            //printf("%p\n", p[k]);
        }
        k++;
    }
    
    free(_p);
    return NULL;
}

//测试分配+free
void* thread_func_melon(void* arg) {
    int N = UNIT_X*8;
    void* _p = malloc(N * sizeof(void*));
    memset(_p, 0, N * sizeof(void*));
    px_t p = (px_t)_p;
    //printf("%p,%p\n", p,p+1);

    int t[8] = {4,8,16,32,64,128,256,512};
    
    for (int n = 0; n < UNIT_X; n++) {
        
        for (int i = 0; i < 8; i++) {
            int size = __sync_add_and_fetch(&g_num,1);
            int _size = (size&(t[i]-1)) + t[i];
            //printf("[%d]size=%d\n", i,size);
            LOCK(lock);
            *p = mln_alloc_m(pool, _size);
            UNLOCK(lock);
            
            if (*p) {
                memset(*p, 0, _size);
                //printf("[%d]size=%d %p\n", i,size,p[size-1]);
            } else{
                __sync_add_and_fetch(&_err_cnt[i],1);
                //printf("error size=%d\n", size);
            }
            p++;
        }
    }
    int k = 0;
    p = (px_t)_p;
    while (k < N) {
        if (p[k]) {
            LOCK(lock);
            mln_alloc_free(p[k]);
            UNLOCK(lock);
            //printf("%p\n", p[k]);
        }
        k++;
    }
    
    free(_p);
    return NULL;
}

//只测试分配
void* thread_func_self_malloc(void* arg) {
    void* p[8];
    int t[8] = {4,8,16,32,64,128,256,512};
    
    for (int n = 0; n < UNIT_X; n++) {
        
        for (int i = 0; i < 8; i++) {
            int size = __sync_add_and_fetch(&g_num,1);
            size = (size&(t[i]-1)) + t[i];
            //printf("[%d]size=%d\n", i,size);
            p[i] = mem_pool_alloc(size);
            if (p[i]) {
                memset(p[i], 0, size);
                
            } else{
                _err_cnt[i]++;
                //printf("error size=%d\n", size);
            }
        }
    }
    
    return NULL;
}
//只测试分配
void* thread_func_melon_malloc(void* arg) {
    void* p[8];
    int t[8] = {4,8,16,32,64,128,256,512};
    for (int n = 0; n < UNIT_X; n++) {
        
        for (int i = 0; i < 8; i++) {
            int size = __sync_add_and_fetch(&g_num,1);
            size = (size&(t[i]*2-1)) + t[i];
            LOCK(lock);
            p[i] = mln_alloc_m(pool, size);
            UNLOCK(lock);
            if (p[i]) {
                memset(p[i], 0, size);
            } else{
                _err_cnt[i]++;
                //printf("error size=%d\n", size);
            }
        }
        for (int i = 0; i < 8; i++) {
            if (p[i]) {
                LOCK(lock);
                //mln_alloc_free(p[i]);
                UNLOCK(lock);
            }
        }
    }
    return NULL;
}

// 验证:
// 常规的申请和释放操作
// 过度申请:向更大的size申请
// 极度申请:更大的size的空间也用完了,返回-1.
#define UNIT 10
int test_1() 
{
    mem_pool_init(3*2048); 
    void* p[UNIT];
    int err_cnt = 0;
    
    for (int i = 0; i < UNIT; i++) {
        int size = 512;
        p[i] = mem_pool_alloc(size);
        if (p[i]) {
            printf("[%d]%p\n",i, p[i]);
            memset(p[i], 0, size);
        } else{
            err_cnt++;
        }
    }
    
    for (int i = 0; i < UNIT; i++) {
        if (p[i]) {
            mem_pool_free(p[i]);
        }
    }
    
    for (int i = 0; i < UNIT; i++) {
        int size = 512;
        p[i] = mem_pool_alloc(size);
        if (p[i]) {
            printf("[%d]%p\n",i, p[i]);
            memset(p[i], 0, size);
        } else{
            err_cnt++;
        }
    }
    
    for (int i = 0; i < UNIT; i++) {
        if (p[i]) {
            mem_pool_free(p[i]);
        }
    }
    if(err_cnt == (UNIT -(3*2))*2)
        printf("[%s] success\n", __FUNCTION__);
    else
        printf("[%s] error\n", __FUNCTION__);
    
    mem_pool_destroy();
}

int main() 
{
    void* p[UNIT];
    int err_cnt = 0;
    struct timespec ts;
    struct timespec ts2;
    int d_t[3] = {0,0,0};
    
    int loop = 0;
    #if 1
    mem_pool_init(UNIT_N * 2048); // 2MB内存池
    
    //多线程测试
    while (loop < LOOP) {
        pthread_t tids[THREADS];
        
        // 开始计时
        clock_gettime(CLOCK_REALTIME, &ts);
        
        for (int i = 0; i < THREADS; i++) {
            pthread_create(&tids[i], NULL, thread_func, NULL);
        }
        
        for (int i = 0; i < THREADS; i++) {
            pthread_join(tids[i], NULL);
        }
        g_num = 0;
        // 结束计时
        clock_gettime(CLOCK_REALTIME, &ts2);
        d_t[0] = (ts2.tv_sec - ts.tv_sec)*10000 + (ts2.tv_nsec/100000) - (ts.tv_nsec/100000);//当前值 0.1ms
        if (d_t[0] > d_t[1]) d_t[1] = d_t[0];//最大值
        d_t[2]+=d_t[0];//总时间
        
        printf("[self][loop=%03d] cur_run_time:%03d (0.1ms) {max_run_time:%03d,avr:%d}[%d,%d,%d,%d,%d,%d,%d,%d]\n", 
        loop, d_t[0], d_t[1], d_t[2]/(loop+1),_err_cnt[0],_err_cnt[1],_err_cnt[2],_err_cnt[3],_err_cnt[4],_err_cnt[5],_err_cnt[6],_err_cnt[7]);
        for (int i = 0; i < 8; i++) {
            //_err_cnt[i] = 0;
        }
        loop++;
    }
    mem_pool_show();
    mem_pool_destroy();
    #endif
    
    #if 0
    /*******************************************************************************************************/
    //多线程测试
    pool = mln_alloc_init(NULL, UNIT_N * 2048);
    loop   = 0;
    d_t[0] = 0;
    d_t[1] = 0;
    d_t[2] = 0;
    while (loop < LOOP) {
        pthread_t tids[THREADS];
        
        // 开始计时
        clock_gettime(CLOCK_REALTIME, &ts);
        
        for (int i = 0; i < THREADS; i++) {
            pthread_create(&tids[i], NULL, thread_func_melon, NULL);
        }
        
        for (int i = 0; i < THREADS; i++) {
            pthread_join(tids[i], NULL);
        }
        g_num = 0;
        // 结束计时
        clock_gettime(CLOCK_REALTIME, &ts2);
        d_t[0] = (ts2.tv_sec - ts.tv_sec)*10000 + (ts2.tv_nsec/100000) - (ts.tv_nsec/100000);//当前值 0.1ms
        if (d_t[0] > d_t[1]) d_t[1] = d_t[0];//最大值
        d_t[2]+=d_t[0];//总时间
        
        printf("[melon][loop=%03d] cur_run_time:%03d (0.1ms) {max_run_time:%03d,avr:%d}[%d,%d,%d,%d,%d,%d,%d,%d]\n", 
        loop, d_t[0], d_t[1], d_t[2]/(loop+1),_err_cnt[0],_err_cnt[1],_err_cnt[2],_err_cnt[3],_err_cnt[4],_err_cnt[5],_err_cnt[6],_err_cnt[7]);
        loop++;
        for (int i = 0; i < 8; i++) {
            _err_cnt[i] = 0;
        }
    }           
    mln_alloc_destroy(pool);
    #endif
    
    printf("Test passed err_cnt = %d\n", err_cnt);
    return 0;
}